print("[RG] ModWorldgenMain is loaded.")

do
	local GLOBAL = GLOBAL
	local rawget = GLOBAL.rawget
	local setmetatable = GLOBAL.setmetatable
	setmetatable(env, {__index = function(t, k) return rawget(GLOBAL, k) end})
end

modvars = {}

modimport "modmain/api.lua"

require "constants"
require "map/level"
Layouts = require("map/layouts").Layouts

local ground_types = {}
do
	local all_tiles = {}
	for k,v in pairs(GROUND)do
		all_tiles[v] = true
	end
	print("[RG] Max tile index: ", #all_tiles)
	for i = 1, #all_tiles do
		if all_tiles[i] == i then
			table.insert(ground_types, i)
		end
	end
end

local Get = require("map/static_layout").Get
function LayoutGet(src, ...)
	local layout = require(src)
	local tiles  = layout.layers[1]
	local index  = 0
	local result = Get(src, ...)
	assert(result ~= nil)
	-- reset tiles
	result.ground = {}

	for y = 1, tiles.height do
		local temp = {}
		for x = 1, tiles.width do
			index = index + 1
			table.insert(temp, tiles.data[index])
		end
		table.insert(result.ground, temp)
	end

	-- print(json.encode(result.ground))
	-- fix index
	result.ground_types = ground_types

	return result
end

function LayoutGet_Landmark(src, opts)
	local data = {
		start_mask = PLACE_MASK.IGNORE_IMPASSABLE_BARREN_RESERVED,
		fill_mask  = PLACE_MASK.IGNORE_IMPASSABLE_BARREN_RESERVED,
		layout_position = LAYOUT_POSITION.CENTER,
	}
	if opts ~= nil then
		for k,v in pairs(opts)do
			data[k] = v
		end
	end
	return LayoutGet(src, data)
end

function RegisterLayout(src, opts)
	Layouts[src] = LayoutGet("map/static_layouts/"..(opts and opts.src or src), opts)
end

function RegisterLandmark(src, opts)
	Layouts[src] = LayoutGet_Landmark("map/static_layouts/"..(opts and opts.src or src), opts)
end

local random = math.random

function RG_AddTask(id, data)
	data.colour = {r=random(),g=random(),b=random(),a=1}
	return env.AddTask(id, data)
end

function RG_AddRoom(id, data)
	data.colour = {r=random(),g=random(),b=random(),a=0.5}
	return env.AddRoom(id, data)
end

for _,v in ipairs{
	"lockandkey",
	"levels",
	"tasks",
}do
	modimport("modworldgenmain/"..v..".lua")
end

local gen = require "map/forest_map"

local function getGen()
	package.loaded["f_m"] = nil
	return require "f_m".Generate
end

if false then
	-- 成功率测试
local LOOP = 100
local failed = 0

local old_G = gen.Generate
function gen.Generate(prefab, map_width, map_height, tasks, world_gen_choices, level_type, level)
	print("[RG]It's a hook!!!!!!!!!!!!")
	print(prefab, map_width, map_height, tasks, world_gen_choices, level_type, level)

	for i = 1, LOOP do
		print(">>>>", i)
		if getGen()(prefab, map_width, map_height, tasks, world_gen_choices, level_type, level) then
			--
		else
			failed = failed + 1
		end

		collectgarbage("collect")
		WorldSim:ResetAll()
	end
	
	print("Faild:", failed, "/", LOOP)
	assert(false, "-------终止--------\n"..failed.."/"..LOOP)
end

else
	gen.Generate = getGen()

end

-- 一种禁用区块分离的思路
local old_gen = gen.Generate
function gen.Generate(prefab, ...)
	local mt = getmetatable(WorldSim).__index
	local SeparateIslands = mt.SeparateIslands
	local ForceConnectivity = mt.ForceConnectivity
	local old_prefab = prefab
	if prefab == "rg_foresttrail" then
		mt.SeparateIslands = function()
			print("[RG] Skip - WorldSim:SeparateIslands()")
		end
	end

	if prefab == "rg_foresttrail" then
		-- draw roads
		prefab = "forest"
	end

	-- if prefab then
	-- 	mt.ForceConnectivity = function()
	-- 		print("[RG] Reparam - WorldSim:ForceConnectivity()")
	-- 		ForceConnectivity(WorldSim, false, false)
	-- 	end
	-- end

	local rt = old_gen(prefab, ...)

	mt.SeparateIslands = SeparateIslands
	mt.ForceConnectivity = ForceConnectivity

	if rt ~= nil then
		rt.map.prefab = old_prefab
	end

	return rt 
end

-- This makes it so that when the world loops, it is a whole loop instead of just a crescent.
AddGlobalClassPostConstruct("map/storygen", "Story", function(self, id, tasks, terrain, gen_params, level)
	local old_SeperateStoryByBlanks = self.SeperateStoryByBlanks
	if level and level.id == "RG_PARAWORLD" then
		function self:SeperateStoryByBlanks(startnode, endnode, ...)
			-- 这里顺便做一个标记，方便后续添加虫洞
			modvars.startnode = startnode
			modvars.endnode   = endnode
			modvars.addparawormhole = true
			old_SeperateStoryByBlanks(self, startnode, endnode, ...)
			-- self.rootNode:LockGraph(startnode.id..'->'..endnode.id, startnode, endnode, {type="none", keys = KEYS.NONE, node=nil})
		end
	end
end)

local START_ID = 114514
local END_ID   = 191981

AddGlobalClassPostConstruct("map/network", "Graph", function(self, id)
	local old_GlobalPrePopulate = self.GlobalPrePopulate
	function self:GlobalPrePopulate(entities, width, height, ...)
		local function DoWormholeLayout(node, isstart)
			local obj_layout = require("map/object_layout")
			local prefab_list = {}
			local data = {
				id = isstart and START_ID or END_ID,
				data = {
					teleporter = {target = isstart and END_ID or START_ID},
				}
			}
		
			local add_fn = {fn=function(...) node:AddEntity(...) end,args={entitiesOut=entities, width=width, height=height, rand_offset = false, debug_prefab_list=prefab_list}}
		
			local layout = obj_layout.LayoutForDefinition("rg_parawormhole_"..(isstart and "start" or "end")) 
			local prefabs = obj_layout.ConvertLayoutToEntitylist(layout)

			for i,p in ipairs(prefabs) do
				if string.find(p.prefab, "wormhole") ~= nil then
					p.properties = data
					break
				end
			end
		
			obj_layout.ReserveAndPlaceLayout(node.id, layout, prefabs, add_fn)
		end

		if modvars.addparawormhole then
			for _, task in pairs(self:GetChildren()) do
				for id, node in pairs(task.nodes) do
					if modvars.startnode == node then
						DoWormholeLayout(node, true)
						modvars.startnode = nil
					elseif modvars.endnode == node then
						DoWormholeLayout(node, false)
						modvars.endnode = nil
					end
				end
			end
			assert(modvars.startnode == nil, "Start node not found.")
			assert(modvars.endnode == nil, "End node not found.")
			modvars.addparawormhole = nil
		else
			old_GlobalPrePopulate(self, entities, width, height, ...)
		end
	end
end)

